<!DOCTYPE html>
<html>

<head>
    <title>Place searches</title>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
    <meta charset="utf-8">
    <style>
        html,
        body,
        table {
            width: 100%;
            height: 100%;
            margin: 0px;
            padding: 0px;
            border: 1px solid #999;
        }
        #map-canvas {
            height: 100%;
            margin: 0px;
            padding: 0px
        }
        #inputbox,
        outputbox {
            width: 80%;
            background-color: #fff;
            border: 1px solid #999;
        }
    </style>
    <script src="https://maps.googleapis.com/maps/api/js?v=3.exp&signed_in=true&libraries=places"></script>
    <script>
        var UPPER_LIMIT = 2000;
        var TIMER_DELAY = 700;
        var map = null;
        var infowindow = null;
        var geocoder = null;
        var outBox = null;
        var apxBox = null;
        var errBox = null;
        var outArr = [];
        var apxArr = [];
        var pinMap = {};

        function initOutput() {
            if (outBox === null) {
                outBox = document.getElementById('outputbox');
                errBox = document.getElementById('errorbox');
                apxBox = document.getElementById('approxbox');
            }
            if (infowindow === null) {
                infowindow = new google.maps.InfoWindow();
            }
            if (geocoder === null) {
                geocoder = new google.maps.Geocoder();
            }
            if (map === null) {
                map = new google.maps.Map(document.getElementById('map-canvas'), {
                    //                    center: pincode,
                    zoom: 12
                });
            }
            pinMap = {};
            outArr = [];
            apxArr = [];
            outBox.options.length = 0;
            apxBox.options.length = 0;
            errBox.options.length = 0;
        }

        function prepareMap(fields) {
            var passcodeKey;
            if (fields.length == 3) {
                var passcodeKeyArr = fields[2].match(/\b\d{6}\b/g)
                if (passcodeKeyArr) {
                    passcodeKey = passcodeKeyArr[0];
                } else {
                    passcodeKey = "110001";
                }
                fields.splice(1, 0, passcodeKey);
            } else {
                passcodeKey = fields[1].match(/\b\d{6}\b/g)[0]
            }
            var arrValue = pinMap[passcodeKey];
            if (arrValue) {
                arrValue[arrValue.length] = fields; //append
            } else {
                arrValue = [fields]
            }
            //            alert(passcodeKey +",inlen:" +arrValue.length + ",arr:" + arrValue)
            pinMap[passcodeKey] = arrValue;
        }

        function handleInfo(fieldsArr, contents, marker) {
            if (fieldsArr && fieldsArr.length > 0) {
                contents = fieldsArr[0] + ">>" + contents;
            }
            var cIdx = outBox.options.length;
            outBox.options[cIdx] = new Option(contents, contents, false, false);
            outArr[cIdx] = [marker, contents];
        }

        function handleAprx(fieldsArr, contents, marker) {
            if (fieldsArr && fieldsArr.length > 0) {
                contents = fieldsArr[0] + ">>" + contents;
            }
            var cIdx = apxBox.options.length;
            apxBox.options[cIdx] = new Option(contents, contents, false, false);
            apxArr[cIdx] = [marker, contents];
        }

        function handleError(fieldsArr, errTxt) {
            //          alert("handleError::" + fieldsArr +", errTxt:" + errTxt )
            if (fieldsArr && fieldsArr.length > 0) {
                errTxt = fieldsArr[0] + ">>" + errTxt;
            }
            errBox.options[errBox.options.length] = new Option(errTxt, errTxt, false, false);
        }

        function splitInput(lines) {
            initOutput();
            if (lines.length > UPPER_LIMIT) {
                alert("Please enter less than " + UPPER_LIMIT + " records at max");
                return;
            }
            for (var i = 0; i < lines.length; i++) {
                var fields = lines[i].split('##');
                if (fields.length < 3) {
                    handleError(fields, 'Invalid input, format allowed: id##[pincode]##place name##location');
                    continue;
                }
                prepareMap(fields);
            }

            cancelTimer();
            intervalTimer = setInterval(function() {
                timerTick()
            }, TIMER_DELAY);
            setTimeout(cancelTimer, (lines.length * 2) * TIMER_DELAY); //safety
        }
        var timerIndex = 0;
        var timerArr = [];
        var intervalTimer = null;

        function timerTick() {
            if (timerIndex > timerArr.length) {
                cancelTimer();
                alert("Search completed");
                return;
            }
            var pinKey = timerArr[timerIndex];
            timerIndex++;
            document.getElementById("currLabel").innerHTML = "processing: " + pinKey + ":" + pinMap[pinKey][0];
            findLatLngFromTxt(pinKey, pinMap[pinKey]);
        }

        function cancelTimer() {
            if (intervalTimer) {
                clearInterval(intervalTimer);
            }

            timerIndex = 0;
            timerArr = [];
            document.getElementById("currLabel").innerHTML = "";

            for (var pinKey in pinMap) {
                timerArr[timerArr.length] = pinKey;
            }
        }

        function findLatLngFromTxt(addrStr, fieldsArr) {
            geocoder.geocode({
                    'address': addrStr,
                    'region': 'in'
                },
                function(results, status) {
                    if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
                        for (var i = 0; i < fieldsArr.length; i++) {
                            findPlace(results, fieldsArr[i]);
                        }
                    } else {
                        var approxLoc = fieldsArr[0][3]; //try here
                        if (approxLoc) {
                            approxLoc = prepareLocation(approxLoc);
                            geocoder.geocode({
                                    'address': approxLoc,
                                    'region': 'in'
                                },
                                function(resultsAprx, status) {
                                    if (status == google.maps.GeocoderStatus.OK && resultsAprx.length > 0) {
                                        for (var i = 0; i < fieldsArr.length; i++) {
                                            findPlace(resultsAprx, fieldsArr[i]);
                                        }
                                    } else {
                                        for (var i = 0; i < fieldsArr.length; i++) {
                                            handleError(fieldsArr[i], "No base location found for: " + approxLoc + ',' + pincode);
                                        }
                                    }
                                }
                            );
                        } else {
                            for (var i = 0; i < fieldsArr.length; i++) {
                                handleError(fieldsArr[i], "No base location mentioned: " + approxLoc + ', no result for:' + pincode);
                            }
                        }
                    }
                }

            );
        }
        var re = /\d/g;

        function prepareLocation(locStr) {
            var location = "";
            var tokens = locStr.replace(/[0-9]{6}/g, "").split(",");
            var tokenCount = 0;
            for (var i = tokens.length - 1; i > 0; i--) {
                var token = tokens[i].trim();
                if (token.length > 0 && !re.test(token) && tokenCount < 3) {
                    location += " " + token;
                    tokenCount++;
                }
            }
            return location;
        }
        var service = null;

        function findPlace(results, fields) {
            var pin = results[0];
            var pinaddr = fields[2].replace(/[ ,]+/g, ",") + "," + pin.formatted_address;
            var pinloc = pin.geometry.location;

            var request = {
                radius: 10000,
                location: pinloc,
                query: fields[2]
            };
            if (!service) {
                service = new google.maps.places.PlacesService(map);
            }

            service.textSearch(request, function(plcResults, status) {
                if (status == google.maps.places.PlacesServiceStatus.OK) {
                    var apxMap = []; //aprx result
                    var apxScore = 0;

                    for (var i = 0; i < plcResults.length; i++) {
                        var place = plcResults[i];
                        var contents = place.name + "||" + place.geometry.location + "||" + place.formatted_address;
                        var marker = new google.maps.Marker({
                            map: map,
                            position: place.geometry.location,
                            title: contents
                        });
                        var newApxScore = getAppxMatch(pinaddr, place.name + "," + place.formatted_address);
                        if (newApxScore > apxScore) {
                            apxScore = newApxScore;
                            apxMap.length = 0;
                            apxMap[apxMap.length] = [contents, marker, place.formatted_address, newApxScore];
                        } else if (newApxScore == apxScore) {
                            apxMap[apxMap.length] = [contents, marker, place.formatted_address, newApxScore];
                        }
                    }

                    if (apxMap.length > 0) {
                        for (var x = 0; x < apxMap.length; x++) {
                            if (apxMap[x][2].indexOf(fields[1]) >= 0) {
                                handleInfo(fields, "Accurate place results (score:" + apxMap[x][3] + ") for keyword/pin: " + fields[2] + ":" + fields[1] + ", place:" + apxMap[x][0], apxMap[x][1]);
                            } else {
                                handleAprx(fields, "Approximate place results (score:" + apxMap[x][3] + ") for keyword/pin: " + fields[2] + ":" + fields[1] + ", place:" + apxMap[x][0], apxMap[x][1]);
                            }
                        }
                    } else {
                        handleError(fields, "Zero aprox. place results for place: " + fields[2] + ", near: " + fields[1]);
                    }
                } else {
                    handleError(fields, "Zero place results for place: " + fields[2] + ", near: " + fields[1]);
                }
            });
        }

        function getAppxMatch(pinaddr, plcaddr) {
            plcaddr = plcaddr.toUpperCase();
            var score = 0;
            var matched = "";
            var pinStr = pinaddr.toUpperCase().split(',');
            for (var i = 0; i < pinStr.length; i++) {
                if (plcaddr.indexOf(pinStr[i].trim()) >= 0) {
                    score++;
                    matched = matched + " " + pinStr[i].trim();
                }
            }
            //alert(plcaddr + ",pinStr:" +pinStr+ ",score:" +score + ",matched:"+ matched)
            return score;
        }

        function infoWinFn(index) {
            var conarr = outArr[index];
            panZoomInfo(conarr);
        }

        function aprxWinFn(index) {
            var conarr = apxArr[index];
            panZoomInfo(conarr);
        }

        function panZoomInfo(conarr) {
            if (conarr === null) {
                alert('No marker present');
                return;
            }
            map.setZoom(15);
            map.panTo(conarr[0].position);
            infowindow.setContent(conarr[1]);
            infowindow.open(map, conarr[0]);
        };

        function copyToPopup(obj) {
                var popupWindow = window.open("", "", "menubar=0,scrollbars=1");
                var arr = obj.options;
                for (var i = 0; i < arr.length; i++) {
                    popupWindow.document.write(arr[i].value);
                    popupWindow.document.write("<br />");
                }
                popupWindow.document.close();
            }
            //
    </script>
</head>

<body>
    <table border="0" width="100%" height="100%">
        <tr height="10%">
            <td>
                <button onclick="copyToPopup(document.getElementById('outputbox'))">export output</button>
                <button onclick="copyToPopup(document.getElementById('approxbox'))">export approx</button>
                <button onclick="copyToPopup(document.getElementById('errorbox'))">export error</button>
                <label id="currLabel"></label>
                <br/>
                <textarea id="inputbox" rows="5" cols="40" onchange="splitInput(this.value.split('\n'))">ID##110001##India Gate</textarea>
            </td>
        </tr>
        <tr height="10%">
            <td>
                <select id="outputbox" size="5" width="200px" onclick="infoWinFn(this.selectedIndex)">
                    <option value="">OUTPUT BOX</option>
                </select>
                <br/>
                <select id="approxbox" size="5" width="200px" onclick="aprxWinFn(this.selectedIndex)">
                    <option value="">APPROX BOX</option>
                </select>
                <br/>
                <select id="errorbox" size="5" width="200px">
                    <option value="">ERROR BOX</option>
                </select>
            </td>
        </tr>
        <tr height="80%">
            <td>
                <div id="map-canvas"></div>
            </td>
        </tr>
    </table>
</body>

</html>